import numpy as na
import sys
import os 
import cPickle
from xml.sax  import make_parser
from CritPoint2 import CritPoint
import re
import matplotlib.pyplot as pyplot
from viewableImg import *
if( sys.platform == 'darwin' ):
    BIND_TEXT = True
else:
    BIND_TEXT = False
def create(parent):
    return browse(parent)

class browse(object):
    def __init__(self,*args,**kwargs):
        """expecting kwargs to contain some of the following keywords:
            data: a list of arrays to visualize
            mask: a list (possibly empty) of corresponding masks
            grayFactor: a multiplicative scaling for the grayscale
            labelScheme: a dictionary of color,label pairs"""
        try:
            #print kwargs.keys()
            self.vi = viewableImg(**kwargs)
            
            self.DEBUG = False
            if( self.DEBUG ): print "browse__init__"
            pointsFile = kwargs.pop('pointsFile',None)
            self.scale = 1
            self.writedir=os.getcwd()
            self.critpoints = []
            self.drawpoints = []

            if( pointsFile == None):
                self.pointsFile = "tmp.pckle"
            else:
                self.pointsFile = pointsFile
            if( pointsFile ):
                self.readCriticalPoints()
                
            self.labelScheme = kwargs.get("labelScheme",{"unlabeled":"Red","labeled":"Green"})
            self.currentLabel = kwargs.pop("defaultLabel")
            if( not self.currentLabel in self.labelScheme.keys() ):
                self.currentLabel = self.labelScheme.keys()[0]

             
            self.filename = os.getcwd()
            self.vi.winlevelimage()
        except Exception, error:
            print "failed in browse.__init__() ", error
            sys.exit()

    def writeCriticalPoints(self):
        try:
            fo = open(self.pointsFile,"wb")
            cPickle.dump(self.critpoints,fo)
            fo.close()
        except Exception, error:
            print "failed in writeCriticalPoints", error
    def readCriticalPoints(self):
        try:
            self.writedir = os.path.dirname(self.pointsFile)
            fo = open(self.pointsFile,"rb")
            newPoints = cPickle.load(fo)
            
            self.critpoints.extend(newPoints)
            fo.close()
        except Exception, error:
            pass
    def findNearestCritPoint(self,p,verbose=False):
        try:
            minind = 0 
            minpoint = self.critpoints[0]
            mindist = (minpoint[0]-p[0])**2+(minpoint[1]-p[1])**2+(minpoint[2]-p[2])**2
            for i in range(1,len(self.critpoints)):
                point = self.critpoints[i]
                dist = (point[0]-p[0])**2+(point[1]-p[1])**2+(point[2]-p[2])**2 
                if( dist < mindist ):
                    mindist = dist
                    minind = i
                    minpoint = point
            if( verbose ):
                print minind, minpoint, mindist
            return minind, minpoint, mindist
        except Exception, error:
            print "failed in findNearestCritPoint", error
            return None

    def deleteNearestCritPoint(self, p ):
        try:
            minind, minpoint, mindist = self.findNearestCritPoint(p)
            if( minind != None ):
                del self.critpoints[minind]
            return minpoint
        except Exception, error:
            print "failed in delete nearest_drawpointXY",error
    def modifyNearestCritPoint(self,p):
        minind, minpoint, mindist = self.findNearestCritPoint(p)
        self.critpoints[minind].setLabel(self.currentLabel)
        self.DrawCritPoints()

    def DrawAllCritPoints(self):
        try:
            self.drawpoints = self.critpoints
        except:
            pass


    def getDisplayScaling(self):
        """return the x-y displaying scaling"""
        scls = self.vi.getScale()
        self.scaling = [self.scale*scls[0],self.scale*scls[1]]
        return self.scaling
    def mapToDisplay(self,cp):
        """map the point cp in image indices to display coordinates"""
        try:
            p =cp.getCrd()
            ds = self.vi.getDSize()
            if( self.vi.cview == 'xy' ):
                dp = [p[0], p[1]]
            elif( self.vi.cview == 'xz' ):
                dp = [p[0], p[2]]
            elif( self.vi.cview == 'yz' ):
                dp = [p[1],p[2]]
            if( self.vi.getFlipUD() ):
                dp[1] = ds[1] - 1 - dp[1]
            if( self.vi.getFlipLR() ):
                dp[0] = ds[0] - 1 - dp[0]
            scls = self.getDisplayScaling()
            dp[0] = int(dp[0]*scls[0]+0.5)
            dp[1] = int(dp[1]*scls[1]+0.5)
            return dp
        except Exception, error:
            print "failed in mapToDisplay", error
    def mapFromDisplay(self,p):
        """map the point p in display coordinates to image indices"""
        scls = self.getDisplayScaling()
        ds = self.vi.getDSize()
        xx = int(p[0]/scls[0])
        yy = int(p[1]/scls[1]) #self.slice.shape[1]
        zz = self.vi.getMaxInView(xx,yy)
        ds = self.vi.getDSize()
        if( self.vi.getFlipUD() ):
            yy = ds[1]-1 - yy 
        if( self.vi.getFlipLR() ):
            xx = ds[0]-1 - xx
        if( self.vi.getView() == 'xy' ):
            return [xx,yy,zz]
        elif( self.vi.getView() == 'xz' ):
            return [xx,zz,yy]
        else:
            return [zz,xx,yy]       
    def DrawCritPointsXY(self):
        #print "DrawCritPointsXY",self.critpoints
        self.drawpoints = []
        plims = self.vi.getPlims()
        ds = self.vi.getDSize()
        #print plims
        for cp in self.critpoints:
            point = cp.getCrd()
            #print plims[0], plims[1], point[2], plims[0] <= point[2] < plims[1]
            if( plims[0] <= point[2] < plims[1] ):
                self.drawpoints.append(cp)
  
    def DrawCritPointsXZ(self):
        try:
            if( self.DEBUG ): print "DrawCritPointsXZ"
            self.drawpoints = []
            plims = self.vi.getPlims()
            ds = self.vi.getDSize()
            for point in self.critpoints:
                if( plims[0] <= point[1] < plims[1] ):
                    self.drawpoints.append(point)
        except:
            pass      
    def DrawCritPointsYZ(self):
        try:
            if( self.DEBUG ): print "DrawCritPointsYZ"
            self.drawpoints = []
            plims = self.vi.getPlims()
            ds = self.vi.getDSize()
            for point in self.critpoints:
                if( plims[0] <= point[0] < plims[1] ):
                    self.drawpoints.append(point)
        except:
            pass
    def DrawCritPoints(self):
        try:
            if( self.DEBUG ): print "DrawCritPoints"
            if( self.vi.mode == 2 ):
                self.drawpoints = self.critpoints[:]
                return
            if( self.vi.getViewType() == 'global' ):
                self.DrawAllCritPoints()
            else:
                if( self.vi.cview == 'xy' ):
                    self.DrawCritPointsXY()
                elif( self.vi.cview == 'xz' ):
                    self.DrawCritPointsXZ()
                else:
                    self.DrawCritPointsYZ()
        except Exception, error:
            print "failed in DrawCritPoints", error

    def ResetScale(self):
        try:
            self.scale = 1
        except:
            pass
    def DecreaseScale(self):
        try:
            self.scale = max(1,self.scale-1)
        except:
            pass
    def IncreaseScale(self):
        try:
            self.scale = self.scale+1
        except:
            pass

    def SetViewXY(self):
        try:
            self.vi.setView(v = 'xy')
            self.DrawCritPoints()
        except Exception, error:
            pass
    def SetViewXZ(self):
        try:
            self.vi.setView(v = 'xz')
            self.DrawCritPoints()
        except Exception, error:
            print "failed in SetViewXZ",error
            pass
    def SetViewYZ(self):
        try:
            self.vi.setView(v = 'yz')
            self.DrawCritPoints()
        except Exception, error:
            print "failed in SetViewYZ", error


    def flipSliceUD(self):
        try:
            self.vi.toggleFlipUD()
            self.vi.winlevelimage()
        except Exception, error:
            print "flipSliceUD",error

    def flipSliceLR(self):
        try:
            self.vi.toggleFlipLR()
            self.vi.winlevelimage()
        except Exception, error:
            print "flipSliceLR",error

def getLabels(filename):
    try:
        fo = open(filename,'r')
        labels = fo.readlines()
        labels = [ l.strip() for l in labels ]
        return labels
    except Exception, error:
        print "failed in getLabelScheme", error
def getColors(filename):
    try:
        fo = open(filename,'r')
        colors = fo.readlines()
        colors = [ c.strip() for c in colors ]
        return colors
    except Exception, error:
        print "failed in getColors", error
        
def getWinLevelSettings(filename):
    try:
        wls = {}
        fo = open(filename,'r')
        data = fo.readlines()
        for d in data[1:]:# first line is header
            dd = d.split(',')
            wls[dd[0]] = {'win':int(dd[1]),'lev':int(dd[2])}
        return wls
    except Exception, error:
        print "failed in getWinLevelSettings", error
        
def getLabelScheme(labels, colors):
    try:
        colorScheme = {}
        # always use the first color uniquely for the first label
        colorScheme[labels[0]] = colors[0]

        numColors = len(colors)-1
        count = 0
        for l in labels[1:]:
            colorScheme[l] = colors[count % numColors +1]
            count += 1
        return colorScheme
    except Exception, error:
        print "failed in getLabelScheme", error
        print labels
        print colors
        return {"unlabeled":"Red","labeled":"Green"}

def getLabels(filename):
    try:
        fo = open(filename,'r')
        labels = fo.readlines()
        labels = [ l.strip() for l in labels ]
        return labels
    except Exception, error:
        print "failed in getLabelScheme", error


